package com.bocloud.cmp.service.app.resource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.app.ApplicationDao;
import com.bocloud.cmp.dao.app.ApplicationOpenshiftClusterInfoDao;
import com.bocloud.cmp.dao.app.OpenshiftClusterDao;
import com.bocloud.cmp.entity.app.resource.Application;
import com.bocloud.cmp.entity.app.resource.ApplicationOpenshiftClusterInfo;
import com.bocloud.cmp.entity.app.resource.OpenshiftCluster;
import com.bocloud.cmp.entity.app.resource.OpenshiftMonitor;
import com.bocloud.cmp.interfaces.app.resource.ApplicationService;
import com.bocloud.cmp.interfaces.app.resource.OpenshiftMonitorService;
import com.bocloud.cmp.service.app.monitor.KubernetesOpenshiftMonitorClient;
import com.bocloud.cmp.service.app.monitor.AppFirstClient;
import com.bocloud.cmp.service.utils.OpenshiftUtil;
import com.bocloud.common.enums.PostDataFormat;
import com.bocloud.common.http.HttpClient;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.Result;
import com.bocloud.common.utils.ListTool;
import io.fabric8.kubernetes.api.model.ReplicationController;

/**
 * openshift平台监控实现类
 * 
 * @author Zaney
 * @data:2017年3月31日
 * @describe:
 */
@Service("openshiftMonitorService")
public class OpenshiftMonitorSeviceImpl implements OpenshiftMonitorService {
	private static Logger logger = LoggerFactory.getLogger(OpenshiftMonitorSeviceImpl.class);
	private static final String OPENSHIFT_PORT = ":8443";
	private static final String HTTPS_PROXY = "https://";
	private static final String SERVER_ACOCUNT_NAME = "/api/v1/namespaces/management-infra/serviceaccounts/management-admin";
	private static final String SERVER_ACOCUNT_TOKEN = "/api/v1/namespaces/management-infra/secrets/";
	@Autowired
	private ApplicationDao applicationDao;
	@Autowired
	private KubernetesOpenshiftMonitorClient openshiftMonitorClient;
	@Autowired
	private OpenshiftClusterDao openshiftClusterDao;
	@Autowired
	private ApplicationOpenshiftClusterInfoDao applicationOpenshiftClusterInfoDao;
	@Autowired
	private AppFirstClient appFirstClient;
	@Autowired
	private OpenshiftUtil oseUtil;
	@Autowired
	private ApplicationService applicationService;
	
	@Override
	public BsmResult getAppMonitor(OpenshiftMonitor monitor){
		JSONObject jsonObject = new JSONObject();
		try {
			//1、获取应用集群关系表
			ApplicationOpenshiftClusterInfo applicationOpenshiftClusterInfo = 
					applicationOpenshiftClusterInfoDao.getApplicationOpenshiftClusterInfo(monitor.getAppId());
			if (null == applicationOpenshiftClusterInfo) {
				logger.warn("该应用没有对应的集群");
				return new BsmResult(false, "该应用没有对应的集群");
			}
			//2、获取集群信息
			OpenshiftCluster openshiftCluster = openshiftClusterDao.query(applicationOpenshiftClusterInfo.getOpenshiftClusterId());
			if (null == openshiftCluster) {
				logger.warn("集群不存在");
				return new BsmResult(false, "集群不存在");
			}
			// 3、获取应用信息
			Application application = null;
			application = applicationDao.query(monitor.getAppId());
			if (null == application) {
				logger.warn("应用不存在");
				return new BsmResult(false, "应用不存在");
			}
			//4、获取lables
			JSONArray labels = getLabels(openshiftCluster, application);
			if (ListTool.isEmpty(labels)) {
				return new BsmResult(true, "该应用没有对应的部署RC");
			}
			//5、获取token
			String token = getToken(openshiftCluster.getProxyUrl());
			logger.error("token 信息 :"+token);
			if (null != token) {
				monitor.setToken(token);
				//6、获取数据
				List<JSONObject> objects = getBatch(monitor, labels);
				if (ListTool.isEmpty(objects)) {
					return new BsmResult(false, "获取数据失败");
				}
				//7、数据处理
				jsonObject = processData(objects);
			}else{
				jsonObject.put("keys", new JSONArray());// 时间轴
				jsonObject.put("values", new JSONArray());
			}
			return new BsmResult(true, jsonObject, "获取数据成功");
		} catch (Exception e) {
			logger.error("获取数据异常", e);
			return new BsmResult(false, "获取数据失败");
		}
	}

	@Override
	public BsmResult getKubernetesMonitor(OpenshiftMonitor monitor) {
		//最终储存数值的对象
		JSONObject data = new JSONObject();
		//时间
		JSONArray dates = new JSONArray();
		//network格式处理需要的对象
		JSONObject networkRx = new JSONObject();
		JSONObject networkTx = new JSONObject();
		JSONArray values = new JSONArray();
		JSONObject networkObject = new JSONObject();
		//cpu 格式处理需要的对象
		JSONObject cpuObject = new JSONObject();
		try{
			//获取token
			OpenshiftCluster openshiftCluster = openshiftClusterDao.query(monitor.getId());
			String token = getToken(openshiftCluster.getProxyUrl());
			logger.error("token 信息 :"+token);
			if (null != token) {
				monitor.setToken(token);
				//参数处理
				List<OpenshiftMonitor> monitors = param(monitor);
				//线程池
				List<JSONObject> objects = openshiftMonitorClient.batch(monitors);
				for (JSONObject object : objects) {
					if ("MEMORY".equals(object.get("type"))) {
						JSONObject memory = (JSONObject)object.get("MEMORY");
						dates = (JSONArray)memory.get("keys");
						data.put("MEMORY", memory);
						
					}else if ("CPU".equals(object.get("type"))) {
						cpuObject = (JSONObject)object.get("CPU");
					}else if ("NETWORKRX".equals(object.get("type"))) {
						networkRx = (JSONObject)object.get("NETWORKRX");
					}else{
						networkTx = (JSONObject)object.get("NETWORKTX");
					}
				}
				//network格式处理
				values.add(networkTx);
				values.add(networkRx);
			}else{
				JSONObject memory = new JSONObject();
				memory.put("keys", dates);
				memory.put("values", new JSONArray());
				data.put("MEMORY", memory);
				//cpu values
				cpuObject.put("values", new JSONArray());
			}
			
			
			networkObject.put("keys", dates);//时间轴
			networkObject.put("values", values);
			data.put("NETWORK", networkObject);
			//为cpu赋予时间值
			cpuObject.put("keys", dates);// 时间轴
			data.put("CPU", cpuObject);
			// 5、整理数据
			return new BsmResult(true, data, "获取成功");
		}catch (Exception e) {
			logger.error("获取容器平台监控异常", e);
			return new BsmResult(false, data, "获取容器平台监控异常");
		}
		
	}
	
	/**
	 * 获取Labels
	 * @param openshiftCluster
	 * @param application
	 * @return
	 */
	private JSONArray getLabels(OpenshiftCluster openshiftCluster, Application application){
		JSONArray labels = new JSONArray();
		BsmResult bsmResult = new BsmResult();
		try {
			//1、获取rc labels
			Map<String, String> labelMap = applicationService.getAppLabels(application.getId(), bsmResult);
			if (null != (bsmResult = oseUtil.getRcs(openshiftCluster.getProxyUrl(), labelMap)).getData()) {
				@SuppressWarnings("all")
				List<ReplicationController> rcs = (List<ReplicationController>) bsmResult.getData();
				if (ListTool.isEmpty(rcs)) {
					return null;
				}
				for (ReplicationController rc : rcs) {
					JSONObject object = new JSONObject();
					StringBuffer labelBuffer = new StringBuffer();
					labelBuffer.append("%5E");
					Map<String, String> labelsMap = rc.getSpec().getSelector();
					 for (Map.Entry<String, String> entry : labelsMap.entrySet()) {
						 labelBuffer.append("%28%3F%3D.%2A%5Cb");
						 labelBuffer.append(entry.getKey()).append("%3A").append(entry.getValue());
						 labelBuffer.append("%5Cb%29");
					 }
					 labelBuffer.append(".%2A%24");
					 object.put("namespace", rc.getMetadata().getNamespace());
					 object.put("label", labelBuffer.toString());
					 labels.add(object);
				}
			}
		} catch (Exception e) {
			logger.error("获取rc的labels失败", e);
		}
		return labels;
	}
	/**
	 * 获取数据
	 * @param monitor
	 * @param labels
	 * @return
	 */
	private List<JSONObject> getBatch(OpenshiftMonitor monitor, JSONArray labels){
		//获取参数
		monitor.setStartTime("-15mn");
		monitor.setBucketDuration("60000");
		try {
			List<OpenshiftMonitor> monitors = param(monitor);
			//线程池
			List<JSONObject> objects = appFirstClient.appBatch(monitors, labels);
			return objects;
		} catch (Exception e) {
			logger.error("执行线程池获取数据失败", e);
			return null;
		}
	}
	/**
	 * 数据处理
	 * @param objects
	 * @return
	 */
	private JSONObject processData(List<JSONObject> objects){
		JSONObject jsonObject = new JSONObject();
		JSONArray values = new JSONArray();
		//时间集合
		JSONArray dates = new JSONArray();
		for (JSONObject object : objects) {
			if ("Memory".equals(object.get("name"))) {
				JSONObject memoryObject = new JSONObject();
				JSONArray data = (JSONArray)object.get("data");
				dates = (JSONArray)object.get("dates");
				memoryObject.put("name", "Memory");
				memoryObject.put("data", data);
				values.add(memoryObject);
				
			}else if ("CPU".equals(object.get("name"))) {
				JSONObject cpuObject = new JSONObject();
				JSONArray data = (JSONArray)object.get("data");
				cpuObject.put("name", "CPU");
				cpuObject.put("data", data);
				values.add(cpuObject);
			}else if ("Received".equals(object.get("name"))) {
				JSONObject networkRx = new JSONObject();
				JSONArray data = (JSONArray)object.get("data");
				networkRx.put("name", "Network Received");
				networkRx.put("data", data);
				values.add(networkRx);
			}else{
				JSONObject networkTx = new JSONObject();
				JSONArray data = (JSONArray)object.get("data");
				networkTx.put("name", "Network Send");
				networkTx.put("data", data);
				values.add(networkTx);
			}
		}
		// 整理数据
		jsonObject.put("keys", dates);// 时间轴
		jsonObject.put("values", values);
		return jsonObject;
	}
	

	/**
	 * 参数集合
	 * @param monitor
	 * @return
	 */
	public List<OpenshiftMonitor> param(OpenshiftMonitor monitor){
		List<OpenshiftMonitor> monitors = new ArrayList<OpenshiftMonitor>();
		//1、memory参数
		OpenshiftMonitor memoryMonitor = new OpenshiftMonitor();
		BeanUtils.copyProperties(monitor, memoryMonitor);
		if ("pod".equals(monitor.getType())) {
			memoryMonitor.setType("pod_container");
		}
		memoryMonitor.setDescripteName("memory/usage");
		memoryMonitor.setAccess("gauges");
		memoryMonitor.setResourceType("memory");
		//2、cpu
		OpenshiftMonitor cpuMonitor = new OpenshiftMonitor();
		BeanUtils.copyProperties(monitor, cpuMonitor);
		if ("pod".equals(monitor.getType())) {
			cpuMonitor.setType("pod_container");
		}
		cpuMonitor.setAccess("counters");
		cpuMonitor.setDescripteName("cpu/usage");
		cpuMonitor.setResourceType("cpu");
		//3、networkRx
		OpenshiftMonitor netRxMonitor = new OpenshiftMonitor();
		BeanUtils.copyProperties(monitor, netRxMonitor);
		netRxMonitor.setAccess("counters");
		netRxMonitor.setDescripteName("network/rx");
		netRxMonitor.setResourceType("networkRx");
		//4、networkTx
		OpenshiftMonitor netTxMonitor = new OpenshiftMonitor();
		BeanUtils.copyProperties(monitor, netTxMonitor);
		netTxMonitor.setAccess("counters");
		netTxMonitor.setDescripteName("network/tx");
		netTxMonitor.setResourceType("networkTx");
		//5、参数集合
		monitors.add(memoryMonitor);
		monitors.add(cpuMonitor);
		monitors.add(netRxMonitor);
		monitors.add(netTxMonitor);
		return monitors;
	}
	
	public String getToken(String proxyUrl){
		String tokenName = null;
		String url = null;
		Result message = null;
		JSONObject object = null;
		try {
			//获取 token name
			url = HTTPS_PROXY+proxyUrl+OPENSHIFT_PORT+SERVER_ACOCUNT_NAME;
			message = getMessage(url);
			if (message.isFailed()) {
				logger.error("获取serviceAccount 的 token name 失败");
				return null;
			}
			object = JSONObject.parseObject(message.getMessage());
			JSONArray secrets = JSONObject.parseArray(object.get("secrets").toString());
			for (Object secret : secrets) {
				JSONObject parseObject = JSONObject.parseObject(secret.toString());
				Object name = parseObject.get("name");
				if (!name.toString().contains("token")) {
					tokenName = name.toString();
				}
			}
			//获取token 
			url = HTTPS_PROXY+proxyUrl+OPENSHIFT_PORT+SERVER_ACOCUNT_TOKEN+tokenName;
			message = getMessage(url);
			if (message.isFailed()) {
				logger.error("获取token信息失败");
				return null;
			}
			object = JSONObject.parseObject(message.getMessage());
			JSONObject metadata = JSONObject.parseObject(object.getString("metadata"));
			JSONObject annotations = JSONObject.parseObject(metadata.getString("annotations"));
			return annotations.getString("openshift.io/token-secret.value");
		} catch (Exception e) {
			logger.error("获取token异常", e);
			return null;
		}
	}
	/**
	 * httpClient获取数据
	 * @param url
	 * @return
	 */
	public Result getMessage(String url){
		HttpClient httpClient = new HttpClient(1000 * 10);
		httpClient.setDataFormat(PostDataFormat.RAW);
		return httpClient.get(url);
	}
	
}
